/*
 * User: Sepheus Angelus
 * Date: 28/02/2008
 * Time: 16:15
 * 
 */

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.IO;
using System.Collections;

namespace Aphyros_MUD_Server
{
	/// <summary>
	/// Creates a listening socket and handles network events.
	/// </summary>
	public class Listener
	{
		static object BigLock = new object();
		Socket socket;
		/// <summary>
		/// Whether the user is logged in or not.
		/// </summary>
		public bool Login;
		/// <summary>
		/// Unique ID of the user. (Internal purposes)
		/// </summary>
		private uint ID=0;
		/// <summary>
		/// Unique ID of the user.
		/// </summary>
		public uint UniqueID;
		/// <summary>
		/// The Class of the user.
		/// </summary>
		public byte Class;
		/// <summary>
		/// The Gender of the user, 0 is female and 1 is male.
		/// </summary>
		public byte Gender;
		/// <summary>
		/// Access level of the user, highest is 99 and 0 is no access.
		/// </summary>
		public byte Access;
		private static uint UserID=0;
		/// <summary>
		/// Input read in.
		/// </summary>
		public string Line;
		/// <summary>
		/// Room the user currently occupies.
		/// </summary>
		public int Room = 1;
		/// <summary>
		/// Name of the user.
		/// </summary>
		public string Name;
		/// <summary>
		/// State of the user.
		/// </summary>
		public byte State = States.None;
		/// <summary>
		/// Gets input from the user.
		/// </summary>
		private StreamReader Reader;
		/// <summary>
		/// Outputs information to the user.
		/// </summary>
		public StreamWriter Writer;
		static ArrayList connections = new ArrayList();
		
		/// <summary>
		/// Creates a threaded instance of the connection.
		/// </summary>
		/// <param name="socket">Connection socket.</param>
		public Listener(Socket socket)
		{
			this.socket = socket;
			Reader = new StreamReader(new NetworkStream(socket, false));
			Writer = new StreamWriter(new NetworkStream(socket, true));
			new Thread(ClientLoop).Start();
		}

		private void ClientLoop()
		{
			try
			{
				lock (BigLock) { OnConnect(); }
				while (true)
				{
					lock (BigLock)
					{
						foreach (Listener conn in connections) { conn.Writer.Flush(); }
					}
					try { Line = Reader.ReadLine(); }
					catch 
					{ 
						Console.ForegroundColor = ConsoleColor.Red;
						Console.WriteLine("Unsanatized data intercepted from {0}",this.socket.RemoteEndPoint);
						this.Name = "Anonymous";
						Line = null;
						socket.Close();
						connections.Remove(this);
					}
					if (Line == null || Line.ToLower() == "quit")
					{
						foreach (Listener conn in connections)
						{
							conn.Writer.Write(ANSI.BrightYellow);
							if(this.Login == true)
							{
								conn.Writer.WriteLine("{0} disconnected.",this.Name);
							}
							else
							{
								conn.Writer.WriteLine("Anonymous disconnected.");
							}
							conn.Writer.Write(ANSI.White);
							conn.Writer.Flush();
						}
						break;
					}
					lock (BigLock) { ProcessLine(Line); }
				}
			}
			finally
			{
				lock (BigLock)
				{
					socket.Close();
					OnDisconnect();
				}
			}
		}

		private void OnConnect()
		{
			Console.ForegroundColor = ConsoleColor.Magenta;
			Writer.Write(ANSI.BrightBlue);
			Writer.WriteLine("Welcome to the World of {0}, adventurer!",Program.WorldName);
			Writer.WriteLine("State thy name, adventurer");
			UserID += 1;
			this.ID = UserID;
			this.Login = false;
			this.Name = "Anonymous";
			Writer.Write(ANSI.White);
			Console.ForegroundColor = ConsoleColor.Magenta;
			Console.WriteLine("Received connection from {0}",this.socket.RemoteEndPoint.ToString());
			connections.Add(this);
		}

		private void OnDisconnect()
		{
			Console.ForegroundColor = ConsoleColor.Magenta;
			Console.WriteLine("{0} disconnected.",this.Name);
			connections.Remove(this);
			connections.TrimToSize();
		}

		private void ProcessLine(string Line)
		{
			CommandParser.Parse(Line,this,connections);
		}
	}
}
